好哩前面介紹完selenium功能,這裡就要介紹用python實作環境的類別囉!
我們這會實作三個類別:Game、DinoAgent、Game_state。Gam實作selenium語法,DinoAgent包Game,重新命名function以及遊戲初始化,Game_state會在包前面兩個類別,內容的邏輯包含reward的設計跟抓取畫面。
接下來把我們上章的小恐龍實體化,在__init__實現class的屬性:
class Game:
def __init__(self,custom_config=True):
chrome_options = Options()
chrome_options.add_argument("disable-infobars")
chrome_options.add_argument("--mute-audio")
self._driver = webdriver.Chrome(executable_path = chrome_driver_path,chrome_options=chrome_options)
self._driver.set_window_position(x=-10,y=0)
self._driver.get('chrome://dino')
self._driver.execute_script("Runner.config.ACCELERATION=0")
self._driver.execute_script(init_script)
# 這邊用class function:
def get_crashed(self): # 確定小恐龍有無因撞到障礙物結束遊戲
return self._driver.execute_script("return Runner.instance_.crashed")
def get_playing(self): # 確認在遊戲過程狀態中有無結束遊戲
return self._driver.execute_script("return Runner.instance_.playing")
def restart(self): # 重啟遊戲
self._driver.execute_script("Runner.instance_.restart()")
def press_up(self): # 往上跳躍
self._driver.find_element_by_tag_name("body").send_keys(Keys.ARROW_UP)
def get_score(self): # 取得分數
score_array = self._driver.execute_script("return Runner.instance_.distanceMeter.digits")
score = ''.join(score_array) # the javascript object is of type array with score in the formate[1,0,0] which is 100.
return int(score)
def pause(self): # 暫停
return self._driver.execute_script("return Runner.instance_.stop()")
def resume(self): # 重啟暫停狀態
return self._driver.execute_script("return Runner.instance_.play()")
def end(self): # 結束selenium
self._driver.close()
dinoagent其實就Game本體,差別在function命名的更直覺,以及因為有讓小恐龍先跳第一步,做整個遊戲的開始:
class DinoAgent:
def __init__(self,game): #takes game as input for taking actions
self._game = game
self.jump(); # 要先跳第一步,遊戲才能開始
def is_running(self):
return self._game.get_playing()
def is_crashed(self):
return self._game.get_crashed()
def jump(self):
self._game.press_up()
def duck(self): # 這邊有實作往下,但實際上我們不會用到,進階版如果有直撲而來的鳥就有需要了。
self._game.press_down()
Game_state把剛介紹兩個物件兼包進去了。初始化後就可實現function-get_state,之後就可把agent輸出的action,輸入進去,建立變數例如reward跟terimnat,接著用selenium跟環境擷取畫面,再把這三個值回傳:
class Game_sate:
def __init__(self,agent,game):
self._agent = agent
self._game = game
self._display = show_img() # 顯示小畫面
self._display.__next__() # python語法,產生iter效果
# 這邊先介紹要輸入的動作action,action[0]為不跳,action[1]為跳
def get_state(self,actions):
score = self._game.get_score() # 跟selenium要最新畫面
reward = 0.1 # 先設定reward=0.1,只要能持續在場上皆會有0.1獎勵
is_over = False # 遊戲是否結束
if actions[1] == 1: # 決定是否跳躍
self._agent.jump()
image = grab_screen(self._game._driver) # 圖像前處理,下章介紹
self._display.send(image) # 傳送畫面到小視窗
if self._agent.is_crashed(): # 確定是否結束
self._game.restart() # 重新開啟
reward = -1 # 給負獎懲
is_over = True # 確認結束
return image, reward, is_over #return the Experience tuple
# get_state對照gym就是step,這裡也會回傳下個state、獎勵跟terminate。
到這基本把核心環境(environment)講完哩,reward如何設計是在環境裡實現的,基本上手操作過一次,以後未來玩其他遊戲都沒什麼問題囉!另外範例程式碼裡面還有grab_screen()跟process_img()的方法之後會再詳解,好哩我們明天見拉~